// Copyright (c) 1996-2002 John Lyon-Smith. All rights reserved.

#pragma once

#include <wxtl\Base.h>
#include <wxtl\StringUtil.h>

#pragma comment(lib, "ws2_32")

namespace wxtl
{
	class SockAddrIn : public SOCKADDR_IN
	{
	public:
		SockAddrIn(UINT port = 0, const TCHAR* pSockAddr = NULL) throw(...)
		{
			set(port, pSockAddr);
		}

		void set(UINT port = 0, const TCHAR* pSockAddr = NULL) throw(...)
		{
			sin_family = AF_INET;
			memset(sin_zero, 0, ARRAYSIZE(sin_zero));

			if (NULL == pSockAddr)
			{
				sin_addr.s_addr = INADDR_ANY;
			}
			else
			{
				#ifdef _UNICODE
				string sockAddr(unicodeToAscii(pSockAddr));
				#else
				string sockAddr(pSockAddr);
				#endif
				
				// Convert socket address from string to numeric
				// returns INADDR_NONE if not valid a.b.c.d string
				if (INADDR_NONE == (sin_addr.s_addr = inet_addr(sockAddr.c_str())))
				{
					PHOSTENT pHostEnt;
				
					// might be a host name
					if (NULL == (pHostEnt = ::gethostbyname(sockAddr.c_str())))
						throw _win32_error(WSAGetLastError()); // passed a bad name in!

					memcpy(&sin_addr.s_addr, pHostEnt->h_addr_list[0], sizeof(sin_addr));
				}
			}

			// Convert port number to network byte order
			if (port == 0)
				sin_port = 0;
			else
				sin_port = htons((USHORT) port);
		}

		void setC(UINT port = 0, const CHAR* pSockAddr = NULL) throw(...)
		{
			sin_family = AF_INET;
			memset(sin_zero, 0, ARRAYSIZE(sin_zero));

			if (NULL == pSockAddr)
			{
				sin_addr.s_addr = INADDR_ANY;
			}
			else
			{
				string sockAddr(pSockAddr);

				// Convert socket address from string to numeric
				// returns INADDR_NONE if not valid a.b.c.d string
				if (INADDR_NONE == (sin_addr.s_addr = inet_addr(sockAddr.c_str())))
				{
					PHOSTENT pHostEnt;

					// might be a host name
					if (NULL == (pHostEnt = ::gethostbyname(sockAddr.c_str())))
						throw _win32_error(WSAGetLastError()); // passed a bad name in!

					memcpy(&sin_addr.s_addr, pHostEnt->h_addr_list[0], sizeof(sin_addr));
				}
			}

			// Convert port number to network byte order
			if (port == 0)
				sin_port = 0;
			else
				sin_port = htons((USHORT) port);
		}

		UINT getPort() const throw()
		{
			return ntohs(sin_port);
		}
		
		tstring getDottedAddr() const throw()
		{
			#ifdef _UNICODE
			return asciiToUnicode(::inet_ntoa(sin_addr)); 
			#else
			return string(::inet_ntoa(sin_addr)); 
			#endif
		}
		
		SOCKADDR* ptr() throw() 
		{ 
			return (SOCKADDR*)this; 
		}
		
		bool operator==(const SockAddrIn& sockAddr)
		{
			return (memcmp(&sockAddr, this, sizeof(SOCKADDR_IN)-sizeof(sin_zero)) == 0);
		}

		SockAddrIn& operator=(const SockAddrIn& SockAddr)
		{
			memcpy(this, PBYTE(&SockAddr), sizeof(*this));
			return *this;
		}
	};					
}
